<?php

/**
 * Ignus Framework
 *
 * @author Sergey Palyanov <sergey.palyanov@gmail.com>
 * @link http://code.google.com/p/ignus-php/
 * @license http://apache.org/licenses/LICENSE-2.0
 * @package Ignus
 * @subpackage App
 * @since 0.1
 */

namespace Ignus;

use Ignus\Log\Logger;

/**
 * @package Ignus
 * @subpackage App
 * @since 0.1
 */
class Configurator
{
    /**
     * Loads configuration file
     * @static
     * @return void
     */
    public static function initApp()
    {
        $config = App::getPath('data', 'conf.php');

        if (!(App::isProduction() && file_exists($config)))
            self::parseConfig($config);

        require_once $config;
    }

    /**
     * Loads specific routes from configuration file
     * @static
     * @param Router $router
     * @return void
     */
    public static function initRoutes(Router $router)
    {
        $routes = App::getPath('data', 'routes.php');

        if (!(App::isProduction() && file_exists($routes)))
            self::parseRoutes($routes);

        require_once $routes;
    }

    /**
     * Parses main configuration file
     * @static
     * @param string $filename Path to cached configuration file
     * @return void
     * @throws RuntimeException
     */
    private static function parseConfig($filename)
    {
        $conf = parse_ini_file(App::getPath('conf', 'conf.ini'), true);
        if ($conf === false)
            throw new \RuntimeException("Error parsing config file");
        $lines[] = '<?php ';

        // logging
        $logLevel = Logger::NONE;
        if (isset($conf['log']['level'])) {
            if (!Logger::isLevel($conf['log']['level']))
                throw new \RuntimeException('Invalid logging level '.$conf['log']['level']);
            $logLevel = $conf['log']['level'];
        }
        $lines[] = 'Ignus\Log\LogManager::init("'.$logLevel.'");';

        // logging appender
        if (isset($conf['log']['appender'])) {
            $appender = $conf['log']['appender'];
            if (strpos($appender, '\\') === false)
                $appender = 'Ignus\Log\Append\\' . $appender;

            if (!class_exists($appender, true))
                throw new \RuntimeException("Log appender class $appender doesn't exists");

            $lines[] = 'Ignus\Log\LogManager::setAppender(new '.$appender.'());';
        }

        // localizations
        if (!isset($conf['localization']['lang']))
            throw new \RuntimeException("No localization specified in conf.ini");
        $langs = (array) $conf['localization']['lang'];
        $lines[] = 'Ignus\Localize::init(' . var_export($langs, true). ');';

        // database
        if (isset($conf['db']['dsn'])) {
            $driver = parse_url($conf['db']['dsn'], PHP_URL_SCHEME);
            if ($driver == null)
                throw new \RuntimeException("Invalid DSN specified in conf.ini");

            $options = isset($conf['db']['options'])
                ? ', '.var_export($conf['db']['options'], true)
                : '';
            $lines[] = sprintf('Ignus\EntityManager::init(\'%s\', \'%s\'%s);',
                $driver, $conf['db']['dsn'], $options);
        }

        if (file_put_contents($filename, $lines, LOCK_EX) === false)
            throw new \RuntimeException('Error writing config file "'.$filename.'"');
    }

    /**
     * Parses and caches route configuration file
     * @static
     * @param string $filename Path to cached routes configuration
     * @return void
     * @throws RuntimeException
     */
    private static function parseRoutes($filename)
    {
        $routes = file(App::getPath('conf', 'routes.txt'), FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        $count = count($routes);
        $lines[] = '<?php ';

        for ($i = 0; $i < $count; $i++) {
            $route = ltrim($routes[$i]);
            if (strpos($route, '#') === 0)
                continue;

            list($method, $route) = self::parseRoute($route);
            $lines[] = '$router->registerRoute(\''.$method.'\', ' . var_export($route, true).');';
        }

        if (file_put_contents($filename, $lines, LOCK_EX) === false)
            throw new \RuntimeException('Error writing routes file "'.$filename.'"');
    }

    /**
     * Parse individual route record
     * @static
     * @param string $line Route record line
     * @return array Route entry
     */
    private static function parseRoute($line)
    {
        list($method, $path, $executor) = preg_split('/\s+/', $line, 3, PREG_SPLIT_NO_EMPTY);
        list($controller, $action) = explode('.', $executor);

        $elements = explode('/', trim($path, '/'));
        foreach ($elements as &$part) {
            if (empty($part[0]) || $part[0] != '{')
                continue;

            $part = array(trim($part, '{}'));
        }

        return array(
            strtoupper($method),
            array(
                Router::ROUTE_CONTROLLER    =>  $controller,
                Router::ROUTE_ACTION        =>  $action,
                Router::ROUTE_PATH          =>  $elements,
                Router::ROUTE_ELEMENTS      =>  count($elements),
            )
        );
    }
}
